Scroll to navigation

READV(2) Руководство программиста Linux READV(2)

ИМЯ

readv, writev, preadv, pwritev - чтение или запись данных в несколько буферов

ОБЗОР

#include <sys/uio.h>

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);

ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,
               off_t offset);

ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt,
                off_t offset);


Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

preadv(), pwritev(): _BSD_SOURCE

ОПИСАНИЕ

Системный вызов readv() считывает iovcnt буферов из файла, связанного с файловым дескриптором fd, в буферы, описываемые iov («разнесённый ввод»).

Системный вызов writev() записывает iovcnt буферов, описанных iov, в файл, связанный с файловым дескриптором fd («сборный вывод»).

Указатель iov указывает на массив структур iovec (определён в <sys/uio.h>:


struct iovec {

void *iov_base; /* начальный адрес */
size_t iov_len; /* количество передаваемых байт */ };

Системный вызов readv() работает также как read(2), но считывает несколько буферов.

Системный вызов writev() работает также как write(2), но записывает несколько буферов.

Буферы выбираются в порядке, в каком они указаны в массиве. Это означает, что readv() сначала полностью заполнит iov[0], и только потом перейдёт к iov[1], и так далее. (Если данных недостаточно, то могут быть заполнены не все буферы, на которые указывает iov.) Подобным образом writev() запишет сначала всё содержимое iov[0], затем iov[1], и так далее.

Выполняемые вызовами readv() и writev() пересылки данных атомарны: данные записываются writev() единичным блоком, который не перемешивается с выводом других процессов (см. исключения в pipe(7)); аналогично, readv() гарантированно считывает непрерывный блок данных из файла, независимо от операций чтения из других нитей или процессов, которые имеют файловые дескрипторы, ссылающиеся на это же открытое файловое описание (см. open(2)).

preadv() и pwritev()

В системном вызове preadv() объединены возможности readv() и pread(2). Он выполняет ту же задачу что и readv(), но имеет четвёртый аргумент offset, задающий файловое смещение, по которому нужно выполнить операцию чтения.

В системном вызове pwritev() объединены возможности readv() и pwrite(2). Он выполняет ту же задачу что и writev(), но имеет четвёртый аргумент offset, задающий файловое смещение, по которому нужно выполнить операцию записи.

Файловое смещение не изменяется данными вызовами. Файл, заданный в fd, должен позволять изменение смещения.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении readv() и preadv() возвращается количество считанных байт; вызовы writev() и pwritev() возвращают количество записанных байт. При ошибке возвращается -1, а значение errno устанавливается соответствующим образом.

ОШИБКИ

Вызовы могут возвращать те же ошибки что и read(2) и write(2). Кроме этого, preadv() и pwritev() также могут завершаться с ошибками как lseek(2). Дополнительно, определены следующие ошибки:

Сумма значений iov_len превышает значение ssize_t. Или количество векторов iovcnt меньше нуля или больше разрешённого максимума.

ВЕРСИИ

Вызовы preadv() и pwritev() впервые появились в Linux 2.6.30; поддержка в библиотеке добавлена в glibc 2.10.

СООТВЕТСТВИЕ СТАНДАРТАМ

readv(), writev(): 4.4BSD (впервые появились в 4.2BSD), POSIX.1-2001. В Linux libc5 в качестве типа аргумента iovcnt используется size_t, и int в качестве возвращаемого типа.

preadv(), pwritev(): нет в стандарте, но есть в современных BSD.

ЗАМЕЧАНИЯ

Замечания, касающиеся Linux

POSIX.1-2001 позволяет реализации устанавливать ограничение на количество элементов, которые можно передать в iov. Реализация может объявить это ограничение в IOV_MAX (в файле <limits.h>) или во время выполнения в виде возвращаемого значения sysconf(_SC_IOV_MAX). В Linux данное ограничение, возвращаемое этими механизмами, равно 1024, что равно ограничению ядра. Однако обёрточные функции glibc выполняют дополнительные действия, если обнаруживается, что используемый системный вызов завершился неудачно из-за превышения этого ограничения. В случае readv() обёрточная функция выделяет временный буфер, достаточный для всех элементов, указанных в iov, передаёт этот буфер в вызов read(2), копирует данные из буфера в места, указанные в полях iov_base элемента iov, а затем освобождает буфер. Обёрточная функция writev() выполняет аналогичную задачу с помощью временного буфера и вызова write(2).

ДЕФЕКТЫ

Неразумно смешивать вызовы readv() или writev(), работающих с дескрипторами файлов, вместе с функциями из библиотеки stdio; результат непредсказуем и точно не тот, которого вы ожидаете.

ПРИМЕР

Следующий пример кода демонстрирует использование writev():


char *str0 = "hello ";
char *str1 = "world\n";
struct iovec iov[2];
ssize_t nwritten;
iov[0].iov_base = str0;
iov[0].iov_len = strlen(str0);
iov[1].iov_base = str1;
iov[1].iov_len = strlen(str1);
nwritten = writev(STDOUT_FILENO, iov, 2);

СМОТРИТЕ ТАКЖЕ

pread(2), read(2), write(2)

2010-11-17 Linux